package ast

import (
	"mi/compiler/token"
)

func GetFullWidth(node Node) int {
	return node.End() - node.Pos()
}

func IsDeclaration(node Node) bool {
	_, ok := node.(Declaration)
	return ok
}

func IsStatement(node Node) bool {
	_, ok := node.(Statement)
	return ok
}

func GetProjectFileOfNode(node Node) *ProjectFile {
	var pkg = GetPackageOfNode(node)
	if pkg != nil {
		return pkg.ProjectFile
	}
	return nil
}

func GetPackageOfNode(node Node) *Package {
	for !isNil(node) && !IsPackage(node) {
		node = node.Parent()
	}

	return node.(*Package)
}

func GetSourceFileOfNode(node Node) *SourceFile {
	for !isNil(node) && !IsSourceFile(node) {
		node = node.Parent()
	}
	return node.(*SourceFile)
}

func NodeIsMissing(node Node) bool {
	if isNil(node) {
		return true
	}

	return node.Pos() == node.End() &&
		node.Pos() >= 0 &&
		!(IsTokenNode(node) && node.(*TokenNode).Token == token.EndOfFile)
}

func HasModifier(node Node, flags ModifierFlags) bool {
	return (GetModifierFlags(node) & flags) != 0
}

func IsSuperCall(n Node) bool {
	expr, ok := n.(*CallExpression)
	return ok && IsSuperExpression(expr.Expression)
}

func IsDeclarationFile(file *SourceFile) bool {
	return file.IsDeclarationFile
}

func FirstValidNode(node1 Node, node2 Node) Node {
	if !isNil(node1) {
		return node1
	}
	return node2
}

func GetCombinedModifierFlags(node Node) ModifierFlags {
	var flags = GetModifierFlags(node)
	return flags
}

// Returns the ast flags for this ast and all relevant parent nodes.  This is done so that
// nodes like variable declarations and binding elements can returned a view of their flags
// that includes the modifiers from their container.  i.e. flags like export/declare aren't
// stored on the variable declaration directly, but on the containing variable statement
// (if it has one).  Similarly, flags for let/const are store on the variable declaration
// list.  By calling this function, all those flags are combined so that the client can treat
// the ast as if it actually had those flags.
func GetCombinedNodeFlags(node Node) NodeFlags {
	var flags = node.Flags()
	return flags
}

func IsInAmbientContext(node Node) bool {
	for node != nil {
		if IsSourceFile(node) && node.(*SourceFile).IsDeclarationFile {
			return true
		}
		node = node.Parent()
	}
	return false
}

// True if the given identifier, string literal, or number literal is the name of a declaration ast
func IsDeclarationName(name Node) bool {
	if !IsIdentifier(name) {
		return false
	}

	var parent = name.Parent()
	if IsDeclaration(parent) {
		return GetDeclarationName(parent.(Declaration)) == name
	}

	return false
}

func GetClassExtendsHeritageClauseElement(node ObjectLike) *TypeReference {
	var heritageClause = GetHeritageClause(node.GetHeritageClauses(), token.ExtendsKeyword)
	if heritageClause != nil && heritageClause.Types.Len() > 0 {
		return heritageClause.Types.At(0).(*TypeReference)
	}
	return nil
}

func getTypeReferenceArray(list List)[]*TypeReference {
	var result []*TypeReference
	for i := 0; i < list.Len(); i++ {
		result = append(result, list.NodeAt(i).(*TypeReference))
	}
	return result
}

func GetClassImplementsHeritageClauseElements(node ObjectLike) []*TypeReference {
	var heritageClause = GetHeritageClause(node.GetHeritageClauses(), token.ImplementsKeyword)
	if heritageClause != nil {
		return getTypeReferenceArray(heritageClause.Types)
	}
	return nil
}

func GetInterfaceExtendsHeritageClauseElement(node ObjectLike) []*TypeReference {
	var heritageClause = GetHeritageClause(node.GetHeritageClauses(), token.ExtendsKeyword)
	if heritageClause != nil {
		return getTypeReferenceArray(heritageClause.Types)
	}
	return nil
}

func GetHeritageClause(clauses *NodeList, kind token.Token) *HeritageClause {
	for _, n := range clauses.Array() {
		var clause = n.(*HeritageClause)
		if clause.Token == kind {
			return clause
		}
	}
	return nil
}

func HasAncestorNode(node Node, ancestor Node) bool {
	for node != nil {
		if node == ancestor {
			return true
		}
		node = node.Parent()
	}

	return false
}

func IsAnonymousClassDeclarationMethod(node Node) bool {
	return IsMethodDeclaration(node) &&
		IsBodyDeclaration(node.Parent())
}

func GetContainingClassLikeOrInterfaceLike(node Node) ObjectLike {
	for true {
		node = node.Parent()
		if isNil(node) {
			return nil
		}

		if IsClassLike(node) {
			return node.(ObjectLike)
		}


	}
	return nil
}

// Class expression or arrow function
func GetContainingClassExpressionLike(node Node) Node {
	for true {
		node = node.Parent()
		if node == nil || IsClassLike(node) || IsFunctionLike(node) {
			return node
		}
	}
	return nil
}

func GetThisOrSuperContainer(node Node) Node {
	for node != nil {
		switch node.(type) {
		case *MethodDeclaration,
			*ConstructorDeclaration,
			*FieldDeclaration:
			return node
		}
		node = node.Parent()
	}
	return nil
}

func NodeCanBeDecorated(node Node) bool {
	switch node.(type) {
	case *ClassDeclaration,
		*BodyDeclaration,
		*EnumDeclaration,
		*EnumItemDeclaration,
		*InterfaceDeclaration,
		*AnnotationDeclaration,
		*FieldDeclaration,
		*MethodDeclaration,
		*ParameterDeclaration,
		*VariableDeclaration,
		*TypeReference:
		return true
	}

	return false
}

func NodeIsDecorated(node Node) bool {
	return node.GetAnnotations() != nil && NodeCanBeDecorated(node)
}

func GetImmediatelyInvokedFunctionExpression(fun Node) *CallExpression {
	if IsArrowExpression(fun) {
		var prev = fun
		var parent = fun.Parent()
		for IsParenthesizedExpression(parent) {
			prev = parent
			parent = parent.Parent()
		}

		if IsCallExpression(parent) && parent.(*CallExpression).Expression == prev {
			return parent.(*CallExpression)
		}
	}
	return nil
}

func IsIterationStatement(node Node, lookInLabeledStmt bool) bool {
	switch n := node.(type) {
	case *ForStatement,
		*ForOfStatement,
		*DoStatement,
		*WhileStatement:
		return true
	case *LabeledStatement:
		return lookInLabeledStmt && IsIterationStatement(n.Statement, lookInLabeledStmt)
	}

	return false
}

func IsLeftHandSideExpression(node Node) bool {
	switch n := node.(type) {
	case *ElementAccessExpression,
		*SelectorExpression,
		*NewObjectExpression,
		*NewArrayExpression,
		*CallExpression,
		*ClassExpression,
		*ArrayLiteralExpression,
		*ParenthesizedExpression,
		*ArrowExpression,
		*Identifier,
		*ThisExpression,
		*SuperExpression:
		return true

	case *LiteralExpression:
		return n.Token == token.CharLiteral ||
			n.Token == token.IntLiteral ||
			n.Token == token.LongLiteral ||
			n.Token == token.FloatLiteral ||
			n.Token == token.DoubleLiteral ||
			n.Token == token.StringLiteral ||
			n.Token == token.FalseKeyword ||
			n.Token == token.TrueKeyword ||
			n.Token == token.NullKeyword
	}

	return false
}

//func isUnaryExpressionKind(kind token.Token) bool {
//	return kind == token.PrefixUnaryExpression ||
//		kind == token.PostfixUnaryExpression ||
//		kind == token.TypeAssertionExpression ||
//		isLeftHandSideExpressionKind(kind)
//}
//
//func IsUnaryExpression(node *Node) bool {
//	return isUnaryExpressionKind(node.Kind)
//}

//func isExpressionKind(kind token.Token) bool {
//	return kind == token.ConditionalExpression ||
//		kind == token.ArrowFunction ||
//		kind == token.BinaryExpression ||
//		kind == token.AsExpression ||
//		isUnaryExpressionKind(kind)
//}

//func IsExpression(node *Node) bool {
//	return isExpressionKind(node.Kind)
//}
//
func IsLegalExpressionStatement(node *ExpressionStatement) bool {
	switch n := node.Expression.(type) {
	case *PrefixUnaryExpression:
		return n.Operator.Token == token.PlusPlus ||
			n.Operator.Token == token.MinusMinus
	case *PostfixUnaryExpression:
		return true
	case *BinaryExpression:
		return n.Operator.Token.IsAssignmentOperator()
	case *CallExpression:
		return true
	}

	return false
}

//
//func GetDeclarationOfKind(symbol *binder.Symbol, kind token.Token) Decl {
//	for i := 0; i < len(symbol.Decls); i++ {
//		var decl = symbol.Decls[i]
//		if decl.Kind == kind {
//			return decl
//		}
//	}
//	return nil
//}

func GetContainingFunction(node Node) FunctionLike {
	for node != nil {
		node = node.Parent()
		if node == nil {
			break
		}

		switch node.(type) {
		case *ConstructorDeclaration,
			*MethodDeclaration,
			*ArrowFunctionDeclaration:
			return node.(FunctionLike)
		}
	}
	return nil
}

func ModifierToFlag(tok token.Token) ModifierFlags {
	switch tok {
	case token.StaticKeyword:
		return MFStatic
	case token.PublicKeyword:
		return MFPublic
	case token.ProtectedKeyword:
		return MFProtected
	case token.PrivateKeyword:
		return MFPrivate
	case token.AbstractKeyword:
		return MFAbstract
	case token.FinalKeyword:
		return MFFinal
	case token.DefaultKeyword:
		return MFDefault
	}
	return MFNone
}

const modifierFlagsCache = "ModifierFlagsCache"
func GetModifierFlags(node Node) ModifierFlags {
	if node.Get(modifierFlagsCache) != nil {
		return node.Get(modifierFlagsCache).(ModifierFlags)
	}

	var flags = MFNone
	var modifiers = node.GetModifiers()
	if modifiers != nil {
		for i := 0; i < modifiers.Len(); i ++ {
			var modifier = modifiers.At(i).(*Modifier)
			flags |= ModifierToFlag(modifier.Token)
		}
	}

	node.Set(modifierFlagsCache, flags)
	return flags
}

func IsTypeDeclaration(node Node) bool {
	return IsClassLike(node) || IsInterfaceLike(node)
}

func IsClassLike(node Node) bool {
	switch node.(type) {
	case *ClassDeclaration,
		*EnumDeclaration,
		*BodyDeclaration:
		return true
	}
	return false
}

func IsInterfaceLike(node Node) bool {
	switch node.(type) {
	case *InterfaceDeclaration,
		*AnnotationDeclaration:
		return true
	}
	return false
}

func HasRestParameter(s Signature) bool {
	if length := s.GetParameters().Len(); length != 0 {
		var last = s.GetParameters().At(length-1).(*ParameterDeclaration)
		return IsRestParameter(last)
	}
	return false
}

func HasDeclaredRestParameter(s Signature) bool {
	var parameters = s.GetParameters()
	if parameters != nil  &&
		parameters.Len() != 0{
		var last = parameters.Len() - 1
		return IsDeclaredRestParameter(parameters.At(last).(*ParameterDeclaration))
	}
	return false
}

func IsRestParameter(node *ParameterDeclaration) bool {
	return IsDeclaredRestParameter(node)
}

func IsDeclaredRestParameter(node *ParameterDeclaration) bool {
	return node != nil && node.Dots != nil
}

func IsPartOfExpression(node Node) bool {
	var fromParent = false
	switch n := node.(type) {
	case *ThisExpression,
	    *SuperExpression,
	    *ArrayLiteralExpression,
	    *SelectorExpression,
	    *InstanceAccessExpression,
	    *ElementAccessExpression,
	    *CallExpression,
	    *DocumentCallExpression,
	    *NewObjectExpression,
	    *AsExpression,
	    *ParenthesizedExpression,
		*ArrowExpression,
		*PrefixUnaryExpression,
		*PostfixUnaryExpression,
		*BinaryExpression,
		*ConditionalExpression,
		*OmittedExpression:
		return true
	case *Identifier:
		fromParent = true
	case *LiteralExpression:
		switch n.Token {
		case token.ThisKeyword,
			token.SuperKeyword,
			token.NullKeyword,
			token.TrueKeyword,
			token.FalseKeyword:
			return true

		case token.IntLiteral,
			token.LongLiteral,
			token.CharLiteral,
			token.FloatLiteral,
			token.DoubleLiteral,
			token.StringLiteral:
			fromParent = true
		}
	}

	if fromParent {
		var parent = node.Parent()
		switch n := parent.(type) {
		case *VariableDeclaration,
			*ParameterDeclaration,
			*FieldDeclaration:
			return n.(VariableLike).GetInitializer() == node
		case *ExpressionStatement:
			return n.Expression == node
		case *IfStatement:
			return n.Condition == node
		case *DoStatement:
			return n.Condition == node
		case *WhileStatement:
			return n.Condition == node
		case *ReturnStatement:
			return n.Expression == node
		case *CaseClause:
			return n.Expression == node
		case *ThrowStatement:
			return n.Expression == node
		case *SwitchStatement:
			return n.Expression == node
		case *ForStatement:
			return n.Initializer == node && !IsVariableDeclaration(n.Initializer) ||
				n.Condition == node ||
				n.Incrementor == node
		case *ForOfStatement:
			return n.VariableDeclaration == node && !IsVariableDeclaration(n.VariableDeclaration) ||
				n.Expression == node
		case *AsExpression:
			return n.Expression == node
		case *SeeTag:
			return n.Expression == node
		case *CodeLink:
			return n.Expression == node
		default:
			if IsPartOfExpression(parent) {
				return true
			}
		}
	}
	return false
}

type AssignmentKind int
const (
	NoAssign AssignmentKind = iota
	Definite
	Compound
)

func GetAssignmentTargetKind(node Node) AssignmentKind {
	var parent = node.Parent()
	for true{
		switch n := parent.(type) {
		case *BinaryExpression:
			var operator = n.Operator.Token
			if operator.IsAssignmentOperator() {
				if n.Left == node {
					return Definite
				} else {
					return Compound
				}
			}
			return NoAssign

		case *PrefixUnaryExpression:
			var operator = n.Operator.Token
			if operator == token.PlusPlus || operator == token.MinusMinus {
				return Compound
			}
			return NoAssign

		case *PostfixUnaryExpression:
			var operator = n.Operator.Token
			if operator == token.PlusPlus || operator == token.MinusMinus {
				return Compound
			}
			return NoAssign

		case *ParenthesizedExpression:
			node = parent

		default:
			return NoAssign
		}

		parent = node.Parent()
	}

	return NoAssign
}

func IsAssignmentTarget(node Node) bool {
	return GetAssignmentTargetKind(node) != NoAssign
}

func SkipParenthesizedExpression(node Node) Node {
	for IsParenthesizedExpression(node) {
		node = node.Parent()
	}
	return node
}

func GetFunctionLikeBody(node Node) Node {
	switch n := node.(type) {
	case *ConstructorDeclaration:
		return n.Body
	case *MethodDeclaration:
		return n.Body
	case *ArrowExpression:
		return n.Declaration.Body
	case *ArrowFunctionDeclaration:
		return n.Body
	}
	return nil
}

func IsFunctionLike(node Node) bool {
	switch node.(type) {
	case *ConstructorDeclaration,
		*MethodDeclaration,
		*ArrowFunctionDeclaration:
		return true
	}
	return false
}

func GetDeclarationName(node Node) *Identifier {
	switch n := node.(type) {
	// case *BadDeclaration:
	// case *PkgDecl:
	// case *ImportDecl:
	case *FieldDeclaration:
		return n.Name
	case *VariableDeclaration:
		return n.Name
	case *ParameterDeclaration:
		return n.Name
	case *TypeParameterDeclaration:
		return n.Name
	//case *ConstructorDecl:
	case *MethodDeclaration:
		return n.Name
	case *ClassDeclaration:
		return n.Name
	case *EnumItemDeclaration:
		return n.Name
	case *EnumDeclaration:
		return n.Name
	case *InterfaceDeclaration:
		return n.Name
	case *AnnotationDeclaration:
		return n.Name
	case *AliasTag:
		return n.Name
	}

	return nil
}

func NodeIsPresent(node Node) bool {
	return !NodeIsMissing(node)
}

func IsExpression(node Node) bool {
	switch n := node.(type) {
	case *ThisExpression,
		*SuperExpression,
		*SelectorExpression,
		*ElementAccessExpression,
		*CallExpression,
		*NewObjectExpression,
		*ParenthesizedExpression,
		*ArrowExpression,
		*PrefixUnaryExpression,
		*PostfixUnaryExpression,
		*BinaryExpression,
		*ConditionalExpression,
		*OmittedExpression:
		return true

	case *LiteralExpression:
		return n.Token == token.CharLiteral ||
			n.Token == token.IntLiteral ||
			n.Token == token.LongLiteral ||
			n.Token == token.FloatLiteral ||
			n.Token == token.DoubleLiteral ||
			n.Token == token.StringLiteral ||
			n.Token == token.FalseKeyword ||
			n.Token == token.TrueKeyword ||
			n.Token == token.NullKeyword

	case *Identifier:
		var parent = node.Parent()
		switch pn := parent.(type) {
		case *VariableDeclaration,
			*ParameterDeclaration,
			*FieldDeclaration:
			return pn.(VariableLike).GetInitializer() == node
		case *ExpressionStatement:
			return pn.Expression == node
		case *IfStatement:
			return pn.Condition == node
		case *DoStatement:
			return pn.Condition == node
		case *WhileStatement:
			return pn.Condition == node
		case *ReturnStatement:
			return pn.Expression == node
		case *SwitchStatement:
			return pn.Expression == node
		case *CaseClause:
			return pn.Expression == node
		case *ThrowStatement:
			return pn.Expression == node
		case *ForStatement:
			return pn.Condition == node ||
				pn.Incrementor == node
		default:
			if IsExpression(parent) {
				return true
			}
		}
	}
	return false
}

func IsTypeNode(node Node) bool {
	switch node.(type) {
	case *TypeReference,
		*BoundsType,
		*ArrayType,
		*IntrinsicType:
		return true
	}

	if IsIdentifier(node) {
		if !IsQualifiedName(node.Parent()) {
			return false
		}

		node = node.Parent()
	}

	if IsQualifiedName(node) {
		// At this point, ast is either a qualified name or an identifier
		var parent = node.Parent()
		// Do not recursively call isTypeNode on the parent. In the example:
		//
		//     var a: A.B.C
		//
		// Calling isTypeNode would consider the qualified name A.B a type ast. Only C or
		// A.B.C is a type ast.
		switch pn := parent.(type) {
		case *TypeReference,
			*BoundsType,
			*ArrayType,
			*IntrinsicType:
			return true

		case *TypeParameterDeclaration:
			return pn.Constraint == node
		case *FieldDeclaration,
			*ParameterDeclaration,
			*VariableDeclaration:
			return pn.(VariableLike).GetType() == node
		case *ArrowFunctionDeclaration,
			*ConstructorDeclaration,
			*MethodDeclaration:
			return pn.(FunctionLike).GetType() == node
		case *CallExpression:
			return pn.TypeArguments.NodeIndex(node) != -1
		}
	}

	return false
}

func IsTokenNodeAndEqualKind(node Node, kind token.Token) bool {
	switch n := node.(type) {
	case *TokenNode:
		return n.Token == kind
	}
	return false
}

func NodeIndexOf(nodes []Node, node Node) int {
	for i, n := range nodes {
		if n == node {
			return i
		}
	}
	return -1
}

func IsRightSideOfQualifiedNameOrSelectorExpression(node Node) bool {
	switch pn := node.Parent().(type) {
	case *QualifiedName:
		return pn.Right == node
	case *SelectorExpression:
		return pn.Name == node
	case *InstanceAccessExpression:
		return pn.Right == node
	}
	return false
}

func IsTypeReferenceName(node *Identifier) bool {
	switch pn := node.parent.(type) {
	case *TypeReference:
		return pn.Name == node
	}
	return false
}

func IsEntityName(node Node) bool {
	switch n := node.(type) {
	case *Identifier:
		return true
	case *SelectorExpression:
		return IsEntityName(n.Expression)
	case *QualifiedName:
		return IsEntityName(n.Left)
	case *ElementAccessExpression:
		return IsEntityName(n.Expression)
	default:
		return false
	}
}

func IsCallTarget(node Node) bool {
	switch pn := node.Parent().(type) {
	case *CallExpression:
		return pn.Expression == node
	case *DocumentCallExpression:
		return pn.Expression == node
	}
	return false
}

func IsClassBodyFunctionLike(node Node) bool {
	return IsFunctionLike(node) &&
		IsBodyDeclaration(node.Parent())
}

func IsForOfInitializerVariableDeclaration(node Node) bool {
	if IsVariableDeclaration(node) {
		switch pn := node.Parent().(type) {
		case *ForOfStatement:
			return pn.VariableDeclaration == node
		}
	}

	return false
}

func IsConstructCallExpressionTarget(node Node) bool {
	switch pn := node.Parent().(type) {
	case *ConstructorExpression:
		return pn.TypeName == node
	}
	return false
}

func IsFunctionBlock(node Node) bool {
	return IsBlockStatement(node) &&
		IsFunctionLike(node.Parent())
}

func IsTag(node Node) bool {
	switch node.(type) {
	case *AuthorTag,
		*DeprecatedTag,
		*ReturnTag,
		*SeeTag,
		*ExceptionTag,
		*ParameterTag,
		*AliasTag:
	 	return true
	}
	return false
}

func GetTagPrecedence(node Node) int {
	switch node.(type) {
	case *AuthorTag:
		return 0

	case *AliasTag:
		return 1

	case *ParameterTag:
		return 2

	case *ExceptionTag:
		return 3

	case *ReturnTag:
		return 4

	case *SeeTag:
		return 5

	case *DeprecatedTag:
		return 6

	}

	return -1
}

func CanAllowAliasTag(node Node) bool {
	switch node.(type) {
	case *ClassDeclaration,
		*InterfaceDeclaration,
		*EnumDeclaration,
		*AnnotationDeclaration,
		*ConstructorDeclaration,
		*MethodDeclaration,
		*FieldDeclaration,
		*EnumItemDeclaration:
		return true
	}

	return false
}

func IsArrayTypeHasDimension(node *ArrayType) bool {
	var cur Node = node
	for cur != nil && IsArrayType(cur) {
		var arrayType = cur.(*ArrayType)
		if !isNil(arrayType.Dimension) {
			return true
		}
		cur = cur.(*ArrayType).Element
	}

	return false
}

func IsNewArrayType(node *ArrayType) bool {
	for IsArrayType(node.parent) {
		node = node.parent.(*ArrayType)
	}

	switch pn := node.parent.(type) {
	case *NewArrayExpression:
		return pn.Type == node
	}

	return false
}

func IsAnnotationArgumentValueNode(node Node) bool {
	switch node.(type) {
	case *Identifier,
		*SelectorExpression,
		*ArrayLiteralExpression,
		*LiteralExpression:
		return true
	}

	return false
}

func IsAnnotationArgument(node Node) bool {
	switch n := node.(type) {
	case *BinaryExpression:
		return n.Operator.Token == token.Equals && IsIdentifier(n.Left) &&
			IsAnnotationArgumentValueNode(n.Right)
	}

	return false
}

func IsConstantExpression(node Expression) bool {
	switch n := node.(type) {
	case *LiteralExpression:
		return true
	case *ParenthesizedExpression:
		return IsConstantExpression(n.Expression)
	case *BinaryExpression:
		return IsConstantExpression(n.Left) && IsConstantExpression(n.Right)
	case *ConditionalExpression:
		return IsConstantExpression(n.WhenTrue) && IsConstantExpression(n.WhenFalse)
	}

	return false
}

func IsDocNode(node Node) bool {
	switch node.(type) {
	case *DocRoot,
		*Number,
		*Version,
		*PlainText,
		*Header,
		*Bold,
		*Italic,
		*BoldItalic,
		*Paragraph,
		*CodeText,
		*CodeBlock,
		*CodeLink,
		*Link,
		*LineBreak,
		*OrderedList,
		*UnorderedList,
		*ListItem,
		*AuthorTag,
		*AliasTag,
		*ParameterTag,
		*ReturnTag,
		*ExceptionTag,
		*SeeTag,
		*SinceTag,
		*VersionTag,
		*DeprecatedTag:
		return true
	}

	return false
}

func GetDocActiveNode(node Node) Node {
	for IsDocNode(node) {
		node = node.Parent()
	}

	return node
}

func GetContainerDocRoot(node Node) Node {
	for !isNil(node) {
		if IsDocRoot(node) {
			return node
		}

		node = node.Parent()
	}

	return nil
}

func IsTopLevelDeclaration(node Node) bool {
	return IsSourceFile(node.Parent())
}

// Return display name of an identifier
// Computed property names will just be emitted as "[<expr>]", where <expr> is the session
// text of the expression in the computed property.
func DeclarationNameToString(name Node) string {
	if GetFullWidth(name) == 0 {
		return "(Missing)"
	} else {
		if identifier, ok := name.(*Identifier); ok {
			return identifier.Value
		}
		return ""
	}
}
